package org.duang.kit;


import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.bson.types.ObjectId;
import org.duang.db.IdEntity;
import org.duang.db.annotation.Index;
import org.duang.db.annotation.Vo;
import org.duang.db.mongo.MongoDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mongodb.BasicDBObject;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;

public class MongoKit {
	
	private static Logger logger = LoggerFactory.getLogger(MongoKit.class);
	private static ConcurrentMap<String, MongoDao<?>> daoCache = new ConcurrentHashMap<String, MongoDao<?>>();
	private static Map<String, Index> indexMap= new HashMap<String, Index>();
    
    public static DBObject convert2DBFields(Field[] fields) {
    	if(ToolsKit.isEmpty(fields)) return null;
    	DBObject dbo = new BasicDBObject();
    	for (int i = 0; i < fields.length; i++) {
    		dbo.put(fields[i].getName(), true);
		}
		return dbo;
    }
    
   
	public static DBObject convert2DBFields(Collection<String> coll) {
		if(ToolsKit.isEmpty(coll)) return null;
		DBObject fieldsObj = new BasicDBObject();
		for(Iterator<String> it = coll.iterator(); it.hasNext();){
			fieldsObj.put(it.next(), true);
		}
		return fieldsObj;
	}
    
	/**
	 * 构建排序对象
	 * @param fieldName 要排序的字段
	 * @param orderBy	排序字符串，asc或desc
	 * @return
	 */
	public static DBObject builderOrder(String fieldName, String orderBy){
		if(ToolsKit.isEmpty(fieldName) || ToolsKit.isEmpty(orderBy)) return null;
		if(ToolsKit.isEmpty(orderBy)){
			return BasicDBObjectBuilder.start(IdEntity.ID_FIELD, -1).get();		//默认用OID时间来排序
		}else{
			return BasicDBObjectBuilder.start(fieldName, "desc".equalsIgnoreCase(orderBy) ? -1 : 1).get();
		}
	}
	
    public static List<Object> toObjectIds(Object... values){
        List<Object> idList = new ArrayList<Object>();
        int len = values.length;
        for(int i=0; i<len; i++){
            if(values[i] != null){
            	boolean isObjectId = ToolsKit.isValidObjectId((String)values[i]);
            	if(isObjectId){
	                Object dbId = new ObjectId((String)values[i]);
	                idList.add(dbId);
            	}
            }
        }
        return idList;   
    }
    
    @SuppressWarnings("unchecked")
	public static <T> MongoDao<T> get(Class<T> cls){
    	String key = ClassKit.getClassName(cls);
    	MongoDao<?> dao = daoCache.get(key);
    	if(null == dao){
    		dao = new MongoDao<T>(cls);
        	daoCache.put(key, dao);
    	}
    	return (MongoDao<T>)dao;
    }
    
    
    /**
     * 创建索引
     * @param db		database
     * @param coll		collection
     * @param cls		entity class
     * @param key		index key
     */
    public static void createIndex(DBCollection coll, Class<?> cls) throws Exception {
    	Field[] fields = ClassKit.getFields(cls);
    	if(ToolsKit.isEmpty(fields)) return;
    	for(int i=0; i<fields.length; i++){    		
    		if(fields[i].isAnnotationPresent(Vo.class)){    			
    			Class<?> clazz = fields[i].getType();
    			createVoIndexKey(clazz, ClassKit.getBeanName(clazz).toLowerCase()+".");
    			if(indexMap.size() > 0){
    				for(Iterator<Map.Entry<String, Index>> it = indexMap.entrySet().iterator(); it.hasNext();){
    					Map.Entry<String, Index> entry = it.next();
    					createIndex(coll, entry.getKey(), entry.getValue());
    				}
    			}
    			indexMap.clear();
    		}
    		Index index = fields[i].getAnnotation(Index.class);
    		if(ToolsKit.isNotEmpty(index)){
    			createIndex(coll, fields[i].getName(), index);
    		}
    	}
    }
    
    private static void createIndex(DBCollection coll, String key, Index index) throws Exception{
		String name = ToolsKit.isEmpty(index.name()) ? "_"+key+"_" : index.name();
		String type = "text".equalsIgnoreCase(index.type()) ? "1" : "2d";
		String order = index.order().toLowerCase();
		DBObject keys = new BasicDBObject(key, "asc".equals(order) ? Integer.parseInt("1") : Integer.parseInt("-1"));
		if("2d".equals(type)) keys.put(key, type);
		DBObject options = new BasicDBObject("background", true);
		options.put("name", name.toLowerCase());        		
		options.put("unique", index.unique());
		coll.createIndex(keys, options);
    }
    
    private static void createVoIndexKey(Class<?> cls, String key) throws Exception{
		Field[] fields = ClassKit.getFields(cls);
    	if(ToolsKit.isNotEmpty(fields)){
	    	for(Field field : fields){
	    		if(field.isAnnotationPresent(Vo.class)){
	    			Class<?> clazz = field.getType();
	    			key += ClassKit.getBeanName(clazz).toLowerCase()+".";
	    			createVoIndexKey(clazz, key);
	    		} else {
	    			Index index = field.getAnnotation(Index.class);
	    			if(ToolsKit.isNotEmpty(index)){
	    				if(ToolsKit.isNotEmpty(key) && (key.indexOf(".")>-1)){
							String indexKey = key.substring(0, key.lastIndexOf(".")+1) + field.getName();
							indexMap.put(indexKey, index);
						}
	    			}
	    		}
	    	}
    	}
    }
}
